"""
企业微信API模块
包含所有企业微信相关的API调用
"""

import os
import requests
import logging
import time
import uuid

logger = logging.getLogger(__name__)

class WeChatAPI:
    """企业微信API封装类"""
    
    def check_wx_config(self):
        """
        检查企业微信CorpID和CorpSecret配置，并输出日志
        """
        if not self.corp_id:
            logger.error("WX_CORPID（企业微信CorpID）未配置！")
        else:
            logger.info(f"WX_CORPID: {self.corp_id}")
        if not self.corp_secret:
            logger.error("WX_CORPSECRET（企业微信CorpSecret）未配置！")
        else:
            logger.info(f"WX_CORPSECRET: {self.corp_secret[:6]}***（已隐藏）")

    def __init__(self, corp_id=None, corp_secret=None):
        """
        初始化企业微信API
        
        Args:
            corp_id: 企业微信CorpID
            corp_secret: 企业微信应用的Secret
        """
        self.corp_id = corp_id or os.getenv('WX_CORPID')
        self.corp_secret = corp_secret or os.getenv('WX_CORPSECRET')
        self.session = requests.Session()
        self._access_token = None
        self._token_expires = 0
        self.check_wx_config()
    
    def get_access_token(self, force_refresh=False):
        """
        获取企业微信访问令牌
        
        Args:
            force_refresh: 是否强制刷新token
            
        Returns:
            str: access_token，失败返回None
        """
        
        # 检查token是否过期
        if not force_refresh and self._access_token and time.time() < self._token_expires:
            return self._access_token
        
        try:
            url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken"
            params = {
                'corpid': self.corp_id,
                'corpsecret': self.corp_secret
            }
            logger.info(f"获取access_token参数: {params}")
            response = self.session.get(url, params=params, timeout=10)
            if response.status_code == 200:
                data = response.json()
                if data.get('errcode') == 0:
                    self._access_token = data.get('access_token')
                    # token有效期7200秒，提前5分钟刷新
                    self._token_expires = time.time() + 7200 - 300
                    logger.info("获取access_token成功")
                    return self._access_token
                else:
                    logger.error(f"获取access_token失败: {data}")
                    return None
            else:
                logger.error(f"获取access_token请求失败: {response.status_code}")
                return None
        except Exception as e:
            logger.error(f"获取access_token异常: {str(e)}")
            return None
    
    def get_kf_accounts(self, token=None):
        """
        获取客服账号列表
        
        Args:
            token: access_token，如果为None则自动获取
            
        Returns:
            dict: 客服账号列表，失败返回None
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                return None
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/account/list"
            params = {
                'access_token': token
            }
            headers = {'Content-Type': 'application/json'}
            response = self.session.get(url, params=params, headers=headers)
            response.raise_for_status()
            
            result = response.json()
            if result.get('errcode') == 0:
                logger.info("获取客服账号列表成功")
                return result
            else:
                logger.error(f"获取客服账号列表失败: {result}")
                return None
        except Exception as e:
            logger.error(f"获取客服账号列表时发生错误: {str(e)}")
            return None
    
    def get_kf_messages(self, open_kfid=None, cursor=None, token=None):
        """
        获取客服消息
        
        Args:
            open_kfid: 客服账号ID，如果为None则使用环境变量中的KF_ID
            cursor: 游标
            token: access_token，如果为None则自动获取
            
        Returns:
            dict: 客服消息列表，失败返回None
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                return None
            
            # 如果没有提供open_kfid，使用环境变量中的默认值
            if not open_kfid:
                open_kfid = os.getenv('KF_ID')
                if not open_kfid:
                    logger.error("未配置KF_ID，无法获取客服消息")
                    return None
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg"
            params = {
                'access_token': token
            }
            data = {
                "open_kfid": open_kfid
            }
            if cursor:
                data["cursor"] = cursor
            
            headers = {'Content-Type': 'application/json'}
            response = self.session.post(url, params=params, json=data, headers=headers)
            response.raise_for_status()
            
            result = response.json()
            if result.get('errcode') == 0:
                logger.info("获取客服消息成功")
                return result
            else:
                logger.error(f"获取客服消息失败: {result}")
                return None
        except Exception as e:
            logger.error(f"获取客服消息时发生错误: {str(e)}")
            return None
    
    def check_session_status(self, open_kfid, external_userid, token=None):
        """
        检查客服会话状态
        
        Args:
            open_kfid: 客服账号ID
            external_userid: 外部用户ID
            token: access_token，如果为None则自动获取
            
        Returns:
            dict: 会话状态信息
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                logger.error("无法获取access_token")
                return None
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/get"
            params = {
                'access_token': token
            }
            
            # 将open_kfid放在请求体中
            data = {
                'external_userid': external_userid,
                'open_kfid': open_kfid
            }
            
            logger.info(f"📊 检查客服会话状态...")
            logger.info(f"   external_userid: {external_userid}")
            logger.info(f"   open_kfid: {open_kfid}")
            logger.info(f"   data: {data}")
            
            response = self.session.post(url, params=params, json=data, timeout=10)
            logger.info(f"📡 HTTP响应状态码: {response.status_code}")
            logger.info(f"📡 HTTP响应内容: {response.text}")
            
            result = response.json()
            if result.get('errcode') == 0:
                logger.info(f"✅ 会话状态检查成功: {result}")
                return result
            else:
                logger.error(f"❌ 会话状态检查失败: {result}")
                return result
        except Exception as e:
            logger.error(f"❌ 检查会话状态异常: {str(e)}")
            return {"errcode": -1, "errmsg": str(e)}

    def establish_session(self, open_kfid, external_userid, token=None):
        """
        建立客服会话
        
        Args:
            open_kfid: 客服账号ID
            external_userid: 外部用户ID
            token: access_token
            
        Returns:
            bool: 是否成功建立会话
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                logger.error("无法获取access_token")
                return False
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/trans"
            params = {'access_token': token}
            data = {
                'external_userid': external_userid,
                'open_kfid': open_kfid,
                'service_state': 1  # 1表示接待中
            }
            
            logger.info(f"🔄 尝试建立会话...")
            logger.info(f"   external_userid: {external_userid}")
            logger.info(f"   open_kfid: {open_kfid}")
            
            response = self.session.post(url, params=params, json=data, timeout=10)
            result = response.json()
            
            if result.get('errcode') == 0:
                logger.info(f"✅ 会话建立成功")
                return True
            elif result.get('errcode') == 95016:
                logger.warning(f"⚠️ 不允许状态转移 (95016)，尝试先结束会话")
                if self.end_session(open_kfid, external_userid, token):
                    logger.info("✅ 会话已结束，重新尝试建立会话")
                    # 重新尝试建立会话
                    response = self.session.post(url, params=params, json=data, timeout=10)
                    result = response.json()
                    
                    if result.get('errcode') == 0:
                        logger.info(f"✅ 会话重新建立成功")
                        return True
                    elif result.get('errcode') == 95013:
                        logger.info(f"✅ 会话已结束 (95013)，无需重新建立")
                        return True
                    else:
                        logger.error(f"❌ 会话重新建立失败: {result}")
                        return False
                else:
                    logger.error("❌ 无法结束会话，建立会话失败")
                    return False
            elif result.get('errcode') == 95013:
                logger.info(f"✅ 会话已结束 (95013)，无需重新建立")
                return True
            else:
                logger.error(f"❌ 会话建立失败: {result}")
                return False
                
        except Exception as e:
            logger.error(f"❌ 建立会话异常: {str(e)}")
            return False

    def end_session(self, open_kfid, external_userid, token=None):
        """
        结束客服会话
        
        Args:
            open_kfid: 客服账号ID
            external_userid: 外部用户ID
            token: access_token
            
        Returns:
            bool: 是否成功结束会话
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                logger.error("无法获取access_token")
                return False
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/trans"
            params = {'access_token': token}
            data = {
                'external_userid': external_userid,
                'open_kfid': open_kfid,
                'service_state': 4  # 4表示会话结束
            }
            
            logger.info(f"🔄 尝试结束会话...")
            logger.info(f"   external_userid: {external_userid}")
            logger.info(f"   open_kfid: {open_kfid}")
            
            response = self.session.post(url, params=params, json=data, timeout=10)
            result = response.json()
            
            if result.get('errcode') == 0:
                logger.info(f"✅ 会话结束成功")
                return True
            else:
                logger.error(f"❌ 会话结束失败: {result}")
                return False
                
        except Exception as e:
            logger.error(f"❌ 结束会话异常: {str(e)}")
            return False

    def send_kf_message(self, open_kfid, external_userid, msg_type, content, token=None):
        """
        发送客服消息
        
        Args:
            open_kfid: 客服账号ID
            external_userid: 外部用户ID
            msg_type: 消息类型
            content: 消息内容
            token: access_token，如果为None则自动获取
            
        Returns:
            dict: 发送结果，失败返回None
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                logger.error("无法获取access_token")
                return None
            
            # 先检查会话状态
            session_status = self.check_session_status(open_kfid, external_userid, token)
            if session_status and session_status.get('errcode') == 0:
                service_state = session_status.get('service_state', 0)
                logger.info(f"📊 当前会话状态: {service_state}")
                
                # 如果会话状态不是1（接待中）或3（转接中），尝试建立会话
                if service_state not in [1, 3]:
                    logger.warning(f"⚠️ 会话状态不正确 ({service_state})，尝试建立会话")
                    if not self.establish_session(open_kfid, external_userid, token):
                        logger.error("❌ 无法建立会话，发送消息失败")
                        return None
                    logger.info("✅ 会话建立成功，继续发送消息")
                elif service_state == 3:
                    logger.info(f"📤 会话状态为转接中 ({service_state})，继续发送消息")
            
            url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg"
            params = {
                'access_token': token
            }
            
            # 生成唯一的msgid
            unique_msgid = f"wx_{int(time.time())}_{uuid.uuid4().hex[:8]}"
            
            data = {
                "open_kfid": open_kfid,
                "touser": external_userid,  # 使用touser字段
                "msgtype": msg_type,
                "text": {
                    "content": content
                },
                "msgid": unique_msgid  # 添加唯一的msgid
            }
            
            # 添加详细日志
            logger.info(f"📤 准备发送客服消息 (wx_api):")
            logger.info(f"   URL: {url}")
            logger.info(f"   external_userid: {external_userid}")
            logger.info(f"   open_kfid: {open_kfid}")
            logger.info(f"   content: {content}")
            logger.info(f"   msgid: {unique_msgid}")
            logger.info(f"   data: {data}")
            
            headers = {'Content-Type': 'application/json'}
            response = self.session.post(url, params=params, json=data, headers=headers)
            logger.info(f"📡 HTTP响应状态码: {response.status_code}")
            logger.info(f"📡 HTTP响应内容: {response.text}")
            
            response.raise_for_status()
            
            result = response.json()
            if result.get('errcode') == 0:
                logger.info(f"✅ 客服消息发送成功 (wx_api): {result}")
                return result
            elif result.get('errcode') == 95018:
                logger.warning(f"⚠️ 会话状态无效 (95018)，尝试重新建立会话")
                # 尝试重新建立会话
                if self.establish_session(open_kfid, external_userid, token):
                    logger.info("✅ 会话重新建立成功，重试发送消息")
                    # 重新发送消息
                    response = self.session.post(url, params=params, json=data, headers=headers)
                    logger.info(f"📡 重试HTTP响应状态码: {response.status_code}")
                    logger.info(f"📡 重试HTTP响应内容: {response.text}")
                    
                    result = response.json()
                    if result.get('errcode') == 0:
                        logger.info(f"✅ 重试发送客服消息成功 (wx_api): {result}")
                        return result
                    else:
                        logger.error(f"❌ 重试发送客服消息失败 (wx_api): {result}")
                        return None
                else:
                    logger.error("❌ 无法重新建立会话，发送消息失败")
                    return None
            elif result.get('errcode') == 95016:
                logger.warning(f"⚠️ 会话已结束 (95016)，尝试结束并重新建立会话")
                if self.end_session(open_kfid, external_userid, token):
                    logger.info("✅ 会话已结束，尝试重新建立会话")
                    if self.establish_session(open_kfid, external_userid, token):
                        logger.info("✅ 会话重新建立成功，重试发送消息")
                        # 重新发送消息
                        response = self.session.post(url, params=params, json=data, headers=headers)
                        logger.info(f"📡 重试HTTP响应状态码: {response.status_code}")
                        logger.info(f"📡 重试HTTP响应内容: {response.text}")
                        
                        result = response.json()
                        if result.get('errcode') == 0:
                            logger.info(f"✅ 重试发送客服消息成功 (wx_api): {result}")
                            return result
                        else:
                            logger.error(f"❌ 重试发送客服消息失败 (wx_api): {result}")
                            return None
                    else:
                        logger.error("❌ 无法重新建立会话，发送消息失败")
                        return None
                else:
                    logger.error("❌ 无法结束会话，发送消息失败")
                    return None
            elif result.get('errcode') == 95013:
                logger.info(f"✅ 会话已结束 (95013)，消息发送成功")
                return {"errcode": 0, "errmsg": "ok", "msgid": "session_ended"}
            else:
                logger.error(f"❌ 发送客服消息失败 (wx_api): {result}")
                return None
        except Exception as e:
            logger.error(f"❌ 发送客服消息时发生错误 (wx_api): {str(e)}")
            return None
    
    def send_webhook_message(self, webhook_url, content, mentioned_list=None):
        """
        发送webhook消息到企业微信群
        
        Args:
            webhook_url: webhook地址
            content: 消息内容
            mentioned_list: @用户列表
            
        Returns:
            bool: 发送是否成功
        """
        try:
            data = {
                "msgtype": "text",
                "text": {
                    "content": content
                }
            }
            
            if mentioned_list:
                data["text"]["mentioned_list"] = mentioned_list
            
            response = self.session.post(webhook_url, json=data)
            response.raise_for_status()
            
            result = response.json()
            if result.get('errcode') == 0:
                logger.info("webhook消息发送成功")
                return True
            else:
                logger.error(f"webhook消息发送失败: {result}")
                return False
        except Exception as e:
            logger.error(f"发送webhook消息时发生错误: {str(e)}")
            return False 

    def get_kf_servicers(self, open_kfid=None, token=None):
        """
        获取指定客服账号下的所有接待人员userid，并详细排查问题
        Args:
            open_kfid: 客服账号ID，如果为None则使用环境变量中的KF_ID
            token: access_token，如果为None则自动获取
        Returns:
            dict: {"servicers": list, "all_accounts": list, "found": bool, "msg": str}
        """
        try:
            if not token:
                token = self.get_access_token()
            if not token:
                logger.error("无法获取access_token，无法查询接待人员")
                return {"servicers": None, "all_accounts": [], "found": False, "msg": "无法获取access_token"}
            # 获取客服账号列表
            result = self.get_kf_accounts(token=token)
            if not result:
                logger.error("无法获取客服账号列表")
                return {"servicers": None, "all_accounts": [], "found": False, "msg": "无法获取客服账号列表"}
            account_list = result.get('account_list', [])
            if not account_list:
                logger.error("客服账号列表为空")
                return {"servicers": None, "all_accounts": [], "found": False, "msg": "客服账号列表为空"}
            # 打印所有账号信息
            logger.info("所有客服账号信息如下：")
            all_accounts = []
            for account in account_list:
                kfid = account.get('open_kfid')
                servicers = account.get('servicer_userid_list', [])
                logger.info(f"open_kfid: {kfid}, servicer_userid_list: {servicers}")
                all_accounts.append({"open_kfid": kfid, "servicer_userid_list": servicers})
            # 查找目标open_kfid
            if not open_kfid:
                open_kfid = os.getenv('KF_ID')
            for account in account_list:
                if account.get('open_kfid') == open_kfid:
                    servicers = account.get('servicer_userid_list', [])
                    if not servicers:
                        logger.warning(f"找到open_kfid={open_kfid}，但servicer_userid_list为空！")
                        return {"servicers": [], "all_accounts": all_accounts, "found": True, "msg": "servicer_userid_list为空"}
                    logger.info(f"客服账号 {open_kfid} 的接待人员: {servicers}")
                    return {"servicers": servicers, "all_accounts": all_accounts, "found": True, "msg": "ok"}
            # 未找到目标open_kfid
            all_kfids = [a.get('open_kfid') for a in account_list]
            logger.error(f"未找到open_kfid={open_kfid}的客服账号，可用open_kfid有: {all_kfids}")
            return {"servicers": None, "all_accounts": all_accounts, "found": False, "msg": f"未找到open_kfid={open_kfid}"}
        except Exception as e:
            logger.error(f"获取接待人员时发生错误: {str(e)}")
            return {"servicers": None, "all_accounts": [], "found": False, "msg": str(e)} 